"""
@Author  : 刘文豪
@desc    : 工具
@Time    : 2025/8/10
"""
import json
import logging
import os
from typing import Any, Optional

import colorlog  # 导入colorlog库
from logging.handlers import TimedRotatingFileHandler

import requests
import yaml
from selenium import webdriver

"""
日志要封装成类,这样保证使用对象是同一个对象,避免多次调用时使用多个对象
"""


class GetLog:
    __instance = None
    log = None

    # 私有构造方法，防止外部直接实例化
    def __new__(cls, *args, **kwargs):
        if cls.__instance is None:
            cls.__instance = super().__new__(cls)
        return cls.__instance

    @classmethod
    def get_log(cls):
        if cls.log is None:
            # 获取日志器 __name__只识别我打的日志 _name__ 是一个内置变量,通过判断 __name__ 的值，来确定模块是被直接运行还是被导入
            cls.log = logging.getLogger(__name__)

            # 设置日志级别logging.DEBUG logging.INFO
            cls.log.setLevel(logging.DEBUG)

            # logging.getLogger('selenium').setLevel(logging.WARNING)
            # 创建 输出到控制台处理器对象
            st = logging.StreamHandler()
            # 设置文件日志对象
            filepath = os.path.dirname(__file__) + os.sep + "log" + os.sep + "muos.log"
            fh = logging.handlers.TimedRotatingFileHandler(filename=filepath,
                                                           when="midnight",
                                                           interval=1,
                                                           backupCount=3,
                                                           encoding="utf-8")

            # 设置控制台日志格式，带颜色-定义颜色格式（不同级别显示不同颜色）
            color_formatter = colorlog.ColoredFormatter(
                "%(log_color)s%(asctime)s %(levelname)s [%(filename)s:%(funcName)s:%(lineno)d] - %(message)s",
                log_colors={
                    'DEBUG': 'cyan',
                    'INFO': 'green',  # INFO级别显示绿色
                    'WARNING': 'yellow',
                    'ERROR': 'red',
                    'CRITICAL': 'bold_red',
                }
            )

            # 设置文件日志格式
            fmt = "%(asctime)s %(levelname)s [%(filename)s:%(funcName)s:%(lineno)d] - %(message)s"
            formatter = logging.Formatter(fmt)

            # 日志信息格式 设置给 控制台处理器
            st.setFormatter(color_formatter)
            # 将日志格式添加到文件日志对象中
            fh.setFormatter(formatter)

            # 日志信息格式 设置给 控制台处理器
            cls.log.addHandler(st)
            # 将文件日志对象添加到日志器中
            cls.log.addHandler(fh)
        return cls.log


"""
获取要封装成类,这样保证使用对象是同一个对象,避免多次调用时使用多个对象
"""


class GetToken:
    __instance = None
    token = None

    # 私有构造方法，防止外部直接实例化
    def __new__(cls, *args, **kwargs):
        if cls.__instance is None:
            cls.__instance = super().__new__(cls)
        return cls.__instance

    @classmethod
    def get_token(cls):
        if cls.token is None:
            req_data = {
                "param": "59a833f4-c80d-4603-ac48-6ccc8688ff05"
            }
            resp = requests.post(read_yaml_value("/config.yaml", ["web", "gettoken"]), json=req_data)
            cls.token = resp.json().get("data", {}).get("access_token")
        return cls.token


def build_data(filename: str, function_name: str)->list:
    """
    读取分组式JSON文件，提取指定功能的测试数据并转换格式

    :param filename: JSON文件名称
    :param function_name: 功能名称（如"新增"、"编辑"）
    :return: 符合pytest参数化要求的列表，格式为[(desc, req_data, expect), ...]
    """
    try:
        # 读取JSON文件内容
        with open(os.path.dirname(__file__) + filename, 'r', encoding='utf-8') as f:
            data = json.load(f)

        # 获取指定功能的测试用例列表，若不存在则返回空列表
        test_cases = data.get(function_name,
                              [])
        # 转换为pytest参数化所需的格式：(desc, req_data, expect)
        # 可根据测试函数的参数需求调整返回的字段组合
        parametrize_data = []
        for case in test_cases:
            # 从当前用例中提取需要的三个字段
            caseid = case['caseid']  # 用例id
            desc = case['desc']  # 用例描述
            req_data = case['req_data']  # 请求数据
            expect = case['expect']  # 预期结果
            # 把这三个字段组合成一个元组，添加到列表中
            case_tuple = (caseid, desc, req_data, expect)
            parametrize_data.append(case_tuple)
        # print(parametrize_data)
        # 列表推导式写法
        # parametrize_data = [
        #     (case['desc'], case['req_data'], case['expect'])
        #     for case in test_cases
        # ]
        return parametrize_data

    except FileNotFoundError:
        raise FileNotFoundError(f"测试数据文件不存在: {filename}")
    except json.JSONDecodeError:
        raise ValueError(f"JSON文件格式错误: {filename}")
    except KeyError as e:
        raise KeyError(f"测试用例缺少必要字段: {e}")


# 读取json数据
def build_data_old(filename: str):
    with open(os.path.dirname(__file__) + filename, "r", encoding="utf-8") as f:
        data = json.loads(f.read())
    # 获取指定接口的数据，如果不存在则返回空列表

    new_list = []
    for item in data:
        item.pop("desc")
        # 列表套元祖的形式 [(),()]
        new_list.append(tuple(item.values()))
    print(new_list)
    return new_list


def read_yaml_value(file_path: str, keys: list[str]) -> Optional[str]:
    """
    读取YAML文件中指定路径的值

    参数:
        file_path: YAML文件路径
        keys: 键的路径列表，例如["web", "host"]

    返回:
        指定路径的值，如果路径不存在则返回None
    """
    try:
        with open(os.path.dirname(__file__) + file_path, "r", encoding="utf-8") as f:
            data = yaml.safe_load(f)

        # 遍历键路径获取值
        current = data
        for key in keys:
            if isinstance(current, dict) and key in current:
                current = current[key]
            else:
                return None
        return current
    except FileNotFoundError:
        print(f"错误: 文件 {file_path} 不存在")
        return None
    except yaml.YAMLError as e:
        print(f"错误: 解析YAML文件失败 - {e}")
        return None
    except Exception as e:
        print(f"错误: 读取YAML文件时发生异常 - {e}")
        return None

class Driver:
    driver = None
    # 关闭浏览器驱动的开关
    flag = None


    # 初始化驱动
    @classmethod
    def init_driver(cls):
        # 初始化驱动（类方法）
        if cls.driver is None:  # 避免重复创建
            cls.driver = webdriver.Chrome()
        return cls.driver

    # 关闭驱动
    @classmethod
    def quit_driver(cls):
        # 关闭驱动（类方法）
        if cls.driver is not None and cls.flag:
            cls.driver.quit()
            cls.driver = None  # 重置为None，方便下次重新初始化
    @classmethod
    def change_flag(cls, flag):
        cls.flag = flag


if __name__ == '__main__':
    token = GetToken()
    # print(token.get_token())

    # build_data("/data/user.json","新增")
    # build_data_old("/data/user_add.json")
    # 读取host的值
    # host = read_yaml_value("/config.yaml", ["web", "host"])
    # print(f"host: {host}")
    #
    # # 读取gettoken的值
    # gettoken = read_yaml_value("/config.yaml", ["web", "gettoken"])
    # print(f"gettoken: {gettoken}")
